﻿using AutoMapper;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using WMS.FC.Domain.DomainObject.System;
using WMS.FC.Domain.DomainObject.Tasks;
using WMS.FC.Domain.PersistenceObject.Business;
using WMS.FC.Domain.Repository;
using WMS.FC.Domain.Service.Location.Interface;
using WMS.FC.Domain.Service.System;
using WMS.FC.Domain.Service.Tasks.Interface;
using WMS.FC.Domain.Service.Tray.Interface;

namespace WMS.FC.Domain.Service.Tasks
{
    public class GetInboundTaskService : ServiceBase, IGetInboundTaskService
    {
        protected readonly IStationRepository stationRepository;
        protected readonly ITechnologyRepository technologyRepository;
        protected readonly IEquipmentRepository equipmentRepository;
        protected readonly ITaskRepository taskRepository;
        protected readonly ICheckTrayStatusService checkTrayStatusService;
        protected readonly IGetTrayInfoService getTrayInfoService;
        protected readonly IGetTrayProductLineService getTrayProductLineService;
        protected readonly IGetInboundLocationService getInboundLocationService;
        protected readonly IGetTaskCodeService getTaskCodeService;

        public GetInboundTaskService(
            ILogger<ServiceBase> logger,
            IOptions<WmsSettings> options,
            IMapper mapper,
            ICheckTrayStatusService checkTrayStatusService,
            IGetTrayInfoService getTrayInfoService,
            IStationRepository stationRepository,
            IGetTrayProductLineService getTrayProductLineService,
            ITechnologyRepository technologyRepository,
            IEquipmentRepository equipmentRepository,
            IGetInboundLocationService getInboundLocationService,
            ITaskRepository taskRepository,
            IGetTaskCodeService getTaskCodeService)
            : base(logger, options, mapper)
        {
            this.checkTrayStatusService = checkTrayStatusService;
            this.getTrayInfoService = getTrayInfoService;
            this.stationRepository = stationRepository;
            this.getTrayProductLineService = getTrayProductLineService;
            this.technologyRepository = technologyRepository;
            this.equipmentRepository = equipmentRepository;
            this.getInboundLocationService = getInboundLocationService;
            this.taskRepository = taskRepository;
            this.getTaskCodeService = getTaskCodeService;
        }

        public async Task<ActionResult<TaskDO>> GetInboundTask(string? trayBarcode, string? stationCode, UserInfo userInfo)
        {
            var result = new ActionResult<TaskDO>("托盘申请入库任务");
            try
            {
                if (string.IsNullOrWhiteSpace(trayBarcode))
                    return result.ArgumentError("托盘条码不能为空");

                if (string.IsNullOrWhiteSpace(stationCode))
                    return result.ArgumentError("站台编码不能为空");

                var checkTrayStatusResult = await checkTrayStatusService.CheckTrayStatus(trayBarcode);
                if (!checkTrayStatusResult.IsSuccess)
                    return result.Fail(checkTrayStatusResult);

                var getTrayInfoResult = await getTrayInfoService.GetTrayInfo(trayBarcode, true, false, false, true, false, false, userInfo);
                if (!getTrayInfoResult.IsSuccess)
                    return result.Fail(getTrayInfoResult);

                var getTrayProductLineResult = await getTrayProductLineService.GetTrayProductLine(trayBarcode);
                if (!getTrayProductLineResult.IsSuccess)
                    return result.Fail(getTrayProductLineResult);

                var lineCode = getTrayProductLineResult.Data!;
                var trayDO = getTrayInfoResult.Data!;
                var stationPO = await stationRepository.GetStation(lineCode, stationCode);
                if (stationPO == null)
                    return result.BusinessError($"站台:({stationCode}),站台数据未找到");

                var lineTechnologyProcessRoutePO = await technologyRepository.GetLineTechnologyProcessRoute(lineCode, trayDO.CurrentTray.TechnologyProcessCode);
                if (lineTechnologyProcessRoutePO == null)
                    return result.BusinessError($"产线:({lineCode}),工艺工序:({trayDO.CurrentTray.TechnologyProcessCode}),产线工艺工序路径数据未找到");

                if (lineTechnologyProcessRoutePO.StationCode != stationCode)
                    return result.BusinessError($"产线:({lineCode}),工艺工序:({trayDO.CurrentTray.TechnologyProcessCode}),不能在站台:({stationCode}),申请入库");

                var toEquipmentList = await stationRepository.GetToEquipmentList(lineCode, stationCode);
                var scList = await equipmentRepository.GetScList(lineCode, trayDO.CurrentTechnologyProcess!.ZoneCode);
                if (scList.Count == 0)
                    return result.BusinessError($"产线:({lineCode}),区域:({trayDO.CurrentTechnologyProcess!.ZoneCode}),当前没用可用的堆垛机");

                scList = scList.Where(sc => toEquipmentList.Any(entity => entity.Code == sc.Code)).ToList();
                var getTaskCodeResult = await getTaskCodeService.GetTaskCode();
                if (!getTaskCodeResult.IsSuccess)
                    return result.Fail(getTaskCodeResult);

                var getInboundLocationResult = await getInboundLocationService.GetInboundLocation(trayDO.CurrentTechnologyProcess!.ZoneCode, lineCode, scList.Select(entity => entity.Code).ToList(), trayDO, userInfo);
                if (!getInboundLocationResult.IsSuccess)
                    return result.Fail(getInboundLocationResult);

                var locationPO = getInboundLocationResult.Data!;
                var taskPO = new TaskPO
                {
                    WarehouseCode = options.Value.WarehouseCode,
                    Code = getTaskCodeResult.Data!,
                    TypeCode = "TaskType_Inbound",
                    ZoneCode = trayDO.CurrentTechnologyProcess!.ZoneCode,
                    LineCode = lineCode,
                    EquipmentCode = locationPO.EquipmentCode,
                    StateCode = "TaskState_WaitingExecute",
                    StartPointTypeCode = "TaskPointType_Station",
                    StartPointCdoe = stationCode,
                    EndPointTypeCode = "TaskPointType_Location",
                    EndPointCode = locationPO.Code,
                    Priority = 2000,
                    ContainerBarcode = trayDO.CurrentTray.ContainerBarcode,
                    TrayBarcode1 = trayDO.TrayList![0].Barcode,
                    TrayBarcode2 = trayDO.TrayList.Count > 1 ? trayDO.TrayList[1].Barcode : "",
                    TrayBarcode3 = trayDO.TrayList.Count > 2 ? trayDO.TrayList[2].Barcode : "",
                    TotalCellCount = trayDO.CellList.Where(entity => !string.IsNullOrWhiteSpace(entity.Barcode) && !entity.Barcode.StartsWith(options.Value.FakeCellBarcodePrefix, StringComparison.InvariantCultureIgnoreCase)).Count(),
                    MaterialCode = trayDO.TrayMaterial.Code,
                    TechnologyRouteCode = trayDO.CurrentTray.TechnologyRouteCode,
                    TechnologyProcessCode = trayDO.CurrentTray.TechnologyProcessCode,
                };

                var count = await taskRepository.Insert(taskPO, userInfo);
                if (count == 0)
                    return result.BusinessError("新增任务异常");

                result.Data = new TaskDO()
                {
                    Tray = trayDO,
                    Task = taskPO,
                };
            }
            catch (Exception ex)
            {
                return result.Exception(ex);
            }

            return result;
        }
    }
}
